package com.mixsmart.core.dao.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;

import com.mixsmart.core.bean.Paginate;
import com.mixsmart.core.bean.entity.IEntityBean;
import com.mixsmart.core.dao.IQueryDao;
import com.mixsmart.core.helper.PageHelper;
import com.mixsmart.spellsql.ICondition;
import com.mixsmart.utils.CollectionUtils;
import com.mixsmart.utils.ReflectionUtils;

/**
 * 查询实现类(抽象类)
 * @author lmq
 * @version 1.0
 * @since JDK版本大于等于1.6
 * 2016年1月14日
 */
public abstract class AbstractQueryDao extends HibernateDao implements IQueryDao {

	protected Class<? extends IEntityBean> entityClass;
	
	/**
	 * 用于DAO层子类使用的构造函数.
	 * 通过子类的泛型定义取得对象类型Class.
	 */
	public AbstractQueryDao() {
		entityClass = ReflectionUtils.getSuperClassGenricType(getClass());
	}
	
	private static final Logger log = Logger.getLogger(AbstractQueryDao.class);
	
	@SuppressWarnings("unchecked")
	@Override
	public <E> E findUnique(Class<? extends IEntityBean> clazz,ICondition condition) {
		E entity = null;
		log.debug("按条件查询数据...");
		String hql = " from " + clazz.getName();
		HashMap<String, Object> params = null;
		if (null != condition) {
			hql += " " + condition.build();
			params = condition.param();
		}
		log.debug("条件查询HQL[" + hql + "]");
		entity = (E) super.getQuery(hql, params, false, false).uniqueResult();
		return entity;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <E> List<E> finds(Class<? extends IEntityBean> clazz,ICondition condition) {
		List<E> entityList = null;
		log.debug("按条件查询数据...");
		String hql = " from " + clazz.getName();
		HashMap<String, Object> params = null;
		if (null != condition) {
			hql += " " + condition.build();
			params = condition.param();
		}
		log.debug("条件查询HQL[" + hql + "]");
		entityList = super.getQuery(hql, params, false, false).list();
		return CollectionUtils.handleNull(entityList);
	}
	
	@Override
	public <E> Paginate<E> finds(Class<? extends IEntityBean> clazz, ICondition condition, 
			int pageNo, int pageSize) {
		log.debug("按条件查询数据...");
		String hql = " from " + clazz.getName();
		HashMap<String, Object> params = null;
		if (null != condition) {
			hql += " " + condition.build();
			params = condition.param();
		}
		log.debug("条件查询HQL[" + hql + "]");
		return this.commonHandlePage(hql, params, pageNo, pageSize, clazz, 
				this.getTotalCount(hql, params, false), false, false);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <E> List<E> querySql(String sql, HashMap<String, Object> params,Class<?> clazz) {
		Query query = super.getQuery(sql, params, true, false);
		transformer(query, clazz, true);
		return CollectionUtils.handleNull(query.list());
	}

	@Override
	public <E> Paginate<E> querySql(String sql, HashMap<String, Object> params, int pageNo, int pageSize, Class<?> clazz) {
		return this.commonHandlePage(sql, params, pageNo, pageSize, clazz, 
				this.getTotalCount(sql, params, false), true, false);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> queryObjSql(String sql, HashMap<String, Object> params) {
		return CollectionUtils.handleNull(super.getQuery(sql, params, true, false).list());
	}

	@Override
	public Paginate<Object> queryObjSql(String sql, HashMap<String, Object> params, int pageNo, int pageSize) {
		return this.commonHandlePage(sql, params, pageNo, pageSize, null, 
				this.getTotalCount(sql, params, false), true, false);
	}

	@Override
	public Long countSql(String sql, HashMap<String, Object> params) {
		Long count = 0l;
		Object obj = super.getQuery(sql, params, true, false).uniqueResult();
		count = Long.parseLong(obj.toString());
		return count;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public <E> List<E> querySqlFilter(String sql, HashMap<String, Object> params, Class<?> clazz) {
		Query query = super.getQuery(sql, params, true, true);
		transformer(query, clazz, true);
		return CollectionUtils.handleNull(query.list());
	}

	@Override
	public <E> Paginate<E> querySqlFilter(String sql, HashMap<String, Object> params, int pageNo, int pageSize, Class<?> clazz) {
		return this.commonHandlePage(sql, params, pageNo, pageSize, clazz, 
				this.getTotalCount(sql, params, true), true, true);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> queryObjSqlFilter(String sql, HashMap<String, Object> params) {
		return CollectionUtils.handleNull(super.getQuery(sql, params, true, true).list());
	}

	@Override
	public Paginate<Object> queryObjSqlFilter(String sql, HashMap<String, Object> params, int pageNo, int pageSize) {
		return this.commonHandlePage(sql, params, pageNo, pageSize, null, 
				this.getTotalCount(sql, params, true), true, true);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<Object> queryObjHql(String hql, HashMap<String, Object> params) {
		return CollectionUtils.handleNull(super.getQuery(hql, params, false, false).list());
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> queryObjHqlFilter(String hql, HashMap<String, Object> params) {
		return CollectionUtils.handleNull(super.getQuery(hql, params, false, true).list());
	}
	
	@Override
	public Paginate<Object> queryObjHql(String hql, HashMap<String, Object> params, int pageNo, int pageSize) {
		return this.commonHandlePage(hql, params, pageNo, pageSize, null, 
				this.getTotalCount(hql, params, false), false, false);
	}

	@Override
	public Paginate<Object> queryObjHqlFilter(String hql, HashMap<String, Object> params, int pageNo, int pageSize) {
		return this.commonHandlePage(hql, params, pageNo, pageSize, null, 
				this.getTotalCount(hql, params, true), false, true);
	}

	@Override
	public Long countSqlFilter(String sql, HashMap<String, Object> params) {
		Long count = 0l;
		Object obj = super.getQuery(sql, params, true, true).uniqueResult();
		count = Long.parseLong(obj.toString());
		return count;
	}
	
	@Override
	public Long countHql(String hql, HashMap<String, Object> params) {
		Object obj = super.getQuery(hql, params, false, false).uniqueResult();
		return Long.parseLong(obj.toString());
	}

	@Override
	public Long countHqlFilter(String hql, HashMap<String, Object> params) {
		Object obj = super.getQuery(hql, params, false, true).uniqueResult();
		return Long.parseLong(obj.toString());
	}

	/**
	 * 查询语句转换为统计语句
	 * @param statement SQL语句或HQL语句
	 * @return 返回统计语句
	 */
	protected String prepareCount(String statement) {
		String fromStatement = statement;
		fromStatement = org.apache.commons.lang3.StringUtils.substringBeforeLast(fromStatement, "order by");
		if (statement.trim().startsWith("from")) {
			return "select count(*) " + fromStatement;
		}
		return "select count(*) from (" + fromStatement + ") tmp";
	}

	/**
	 * 转换为指定的对象 
	 * @param query 查询对象
	 * @param clazz 要转换的对象
	 * @param isSql 是否SQL语句
	 */
	protected void transformer(Query query, Class<?> clazz, boolean isSql) {
		if (null != clazz) {
			if (clazz.isAssignableFrom(Map.class)) {
				query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
			} else if (clazz.isAssignableFrom(List.class)) {
				query.setResultTransformer(Transformers.TO_LIST);
			} else {
				if(isSql) {
					super.addScalars((SQLQuery) query, clazz);
					query.setResultTransformer(Transformers.aliasToBean(clazz));
				}
			}
		}
	}
	
	/**
	 * 
	 * @param statement SQL语句或HQL语句
	 * @param params 参数 
	 * @param isFilter 是否对SQL语句或HQL语句过滤
	 * @return 返回总记录数
	 */
	protected long getTotalCount(String statement, HashMap<String, Object> params, boolean isFilter) {
		assertStatement(statement);
		String countStatement = prepareCount(statement);
		Long totalCount = 0l;
		if(isFilter)
			totalCount = this.countSqlFilter(countStatement, params);
		else 
			totalCount = this.countSql(countStatement, params);
		return totalCount;
	}
	
	/**
	 * 通用处理页面
	 * @param statement SQL语句或HQL语句
	 * @param params 参数
	 * @param pageNo 页面数
	 * @param pageSize 每页显示数
	 * @param clazz 转换对象
	 * @param isSql 是否为sql语句；是为:true；否则为:false
	 * @param isFilter SQL语句是否过滤
	 * @return 返回分页对象
	 * @
	 */
	protected <E> Paginate<E> commonHandlePage(String statement, HashMap<String, Object> params, 
			int pageNo, int pageSize, Class<?> clazz,long totalCount, boolean isSql, boolean isFilter) {
		Paginate<E> page = null;
		if (totalCount > 0) {
			Query query = super.getQuery(statement, params, isSql, isFilter);
			if (null != clazz)
				this.transformer(query, clazz, isSql);
			page = commonHandlePage(query, pageNo, pageSize, totalCount);
		}
		return page;
	}
	
	/**
	 * 通用处理页面
	 * @param statement SQL语句或HQL语句
	 * @param params 参数
	 * @param pageNo 页面数
	 * @param pageSize 每页显示数
	 * @param clazz 实体对象
	 * @param totalCount 总记录数
	 * @param isFilter SQL语句是否过滤
	 * @return 返回分页对象
	 */
	protected <E> Paginate<E> commonHandlePage(String statement, HashMap<String, Object> params, 
			int pageNo, int pageSize, Class<?> clazz,long totalCount, boolean isFilter) {
		Paginate<E> page = null;
		if (totalCount > 0 && null != clazz) {
			SQLQuery query = (SQLQuery)super.getQuery(statement, params, true, isFilter);
			query.addEntity(clazz);
			page = commonHandlePage(query, pageNo, pageSize, totalCount);
		}
		return page;
	}
	
	/**
	 * 处理分页
	 * @param query  查询对象
	 * @param pageNo 页面数
	 * @param pageSize 每页显示数
	 * @param totalCount 总记录数
	 * @return 返回分页对象
	 */
	@SuppressWarnings("unchecked")
	private <E> Paginate<E> commonHandlePage(Query query, int pageNo, int pageSize,long totalCount) {
		Paginate<E> page = null;
		query.setFirstResult(PageHelper.getStartNum(pageNo, pageSize));
		query.setMaxResults(pageSize);
		List<E> list = query.list();
		if (CollectionUtils.isNotEmpty(list)) {
			page = new Paginate<E>();
			page.setTotalCount(totalCount);
			page.setPageNo(pageNo);
			page.setPageSize(pageSize);
			page.setDatas(list);
		}
		return page;
	}

}
